//
//  CSMACANoVCSInitiator.cpp
//  WiFiMACSim
//
//  Created by Christopher Kemsley on 4/1/12.
//  Copyright (c) 2012 iAppolopolis. All rights reserved.
//

#include "CSMACAVCSInitiatorNoVCS.hpp"
#include "Settings.hpp"

using namespace Sim ;







CSMACANoVCSInitiator :: CSMACANoVCSInitiator ( ID const & name , ID const & inTarget , UInteger inLambdaScalar )
:	TransitionalStateMachineNode<CSMACANoVCSInitiator>	( name , kStateIdle )
,	target				( inTarget )
,	lambdaScalar		( inLambdaScalar )
,	message				( 0 )
,	timer				( )
,	statistics			( std::string("Node ")+name , sIdle )
	{
	timer . skip ( 0 ) ; // start immediately
	
	
	registerStateCallback ( kStateIdle , &CSMACANoVCSInitiator::run_idle , "Idle. Waiting to send RTS" ) ;
	
	// Transaction control
	registerStateCallback ( kStateSendingData , &CSMACANoVCSInitiator::run_sendingData , "Sending data" ) ;
	registerStateCallback ( kStateWaitACKOrDifs , &CSMACANoVCSInitiator::run_waitACK_difs , "Waiting for (ACK) or (difs timeout)" ) ;
	
	
	// VCS States
	registerStateCallback ( kStateVCSSawCTS , &CSMACANoVCSInitiator::run_vcs_saw , "Saw CTS. Waiting for NAV" ) ;
	registerStateCallback ( kStateVCSSawRTS , &CSMACANoVCSInitiator::run_vcs_saw , "Saw RTS. Waiting for NAV" ) ;
	}
CSMACANoVCSInitiator :: ~CSMACANoVCSInitiator ()
	{
	
	}













void	CSMACANoVCSInitiator :: run_idle			( Message * incoming , bool completed , bool isBusy )
	{
	statistics << sIdle ;
	
	if ( timer.isReset() )
		{
		timer . skip ( Settings::shared().poissonSlotCount(lambdaScalar) ) ;
		}
	else if ( timer.isTime() )
		{
		if ( isBusy )
			{
			timer . skipNext ( Settings::shared().uniformBackoff() ) ;
			}
		else
			{
			setState ( kStateSendingData ) ;
			statistics << sTXData ;
			
			UInteger	duration	=	Settings::shared().dataPacketDuration ;
			
			message = new Message ( identity , target , Message::kTypeData , duration ) ;
			Medium::shared() . registerMessage ( message ) ;
			}
		}
	}




void	CSMACANoVCSInitiator :: run_sendingData	( Message * incoming , bool completed , bool isBusy )
	{
	if ( completed )
		{
		/* Statistics */
		if ( message -> status != Message::kStatusSuccessful )
			{
			//std::cout << NodeStamp << "Data Message was never received/handled\n" ;
			statistics <= sTXDataFail ;
			}
		/* Statistics */
		
		message -> release() ;
		message = 0 ;
		
		timer . skipNext ( Settings::shared().DIFSDuration ) ;
		setState ( kStateWaitACKOrDifs ) ;
		statistics << sTXReturn ;
		}
	}

void	CSMACANoVCSInitiator :: run_waitACK_difs	( Message * incoming , bool completed , bool isBusy )
	{
	if ( incoming != 0 )
		{
		if ( incoming->target == identity )
			{
			if ( completed )
				{
				Message & m	=	*incoming ;
				
				if ( m.type != Message::kTypeACK )
					ThrowException ( "CSMACANoVCSInitiator" , "Receieved non-ACK after DATA" , __FILE__,__LINE__ ) ;
				
				timer . reset () ;
				setState ( kStateIdle ) ;
				statistics << sIdle ;
				}
			else
				{
				incoming->status = Message::kStatusSuccessful ;
				}
			}
		}
	else
		{
		if ( timer.isTime() )
			{
			/* Statistics */
			//std::cout << NodeStamp << "Timed out waiting for CTS\n" ;
			statistics <= sTXReturnFail ;
			/* Statistics */
			
			setState ( kStateIdle ) ;
			statistics << sIdle ;
			}
		}
	}



void	CSMACANoVCSInitiator :: run_vcs_saw	( Message * incoming , bool completed , bool isBusy )
	{
	if ( timer.isTime() )
		setState ( kStateIdle ) ;
	}

void	CSMACANoVCSInitiator :: run_waitDifs	( Message * incoming , bool completed , bool isBusy )
	{
	if ( timer.isTime() )
		setState ( kStateIdle ) ;
	}

